package com.zhangxu.microservice.auth.biz.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zhangxu.microservice.auth.biz.dto.CreateResourceDTO;
import com.zhangxu.microservice.auth.biz.dto.ResourceDTO;
import com.zhangxu.microservice.auth.biz.dto.UpdateResourceDTO;
import com.zhangxu.microservice.auth.biz.mapstruct.ResourceConverter;
import com.zhangxu.microservice.auth.biz.service.ResourceService;
import com.zhangxu.microservice.auth.common.enums.ResourceStatusEnum;
import com.zhangxu.microservice.auth.dao.condition.ResourceCondition;
import com.zhangxu.microservice.auth.dao.entity.ResourceDO;
import com.zhangxu.microservice.auth.dao.service.ResourceDao;
import com.zhangxu.microservice.common.context.EmployeeContextHolder;
import com.zhangxu.microservice.common.exception.BizException;
import com.zhangxu.microservice.common.utils.AssertUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 资源服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ResourceServiceImpl implements ResourceService {

    private final ResourceDao resourceDao;
    private final ResourceConverter resourceConverter;

    @Override
    public Long createResource(CreateResourceDTO createResourceDTO) {
        // 检查系统ID是否存在
        AssertUtils.notNull(createResourceDTO.getSystemId(), "系统ID不能为空");
        
        // 检查资源编码是否已存在
        ResourceDO existingResource = resourceDao.getByCode(createResourceDTO.getCode(), createResourceDTO.getSystemId());
        if (existingResource != null) {
            throw new BizException("资源编码已存在");
        }

        // 转换并保存资源
        ResourceDO resourceDO = resourceConverter.toResourceDO(createResourceDTO);
        resourceDO.setStatus(ResourceStatusEnum.INIT);
        resourceDO.setCreateBy(EmployeeContextHolder.get().getId());
        resourceDO.setUpdateBy(EmployeeContextHolder.get().getId());
        resourceDao.save(resourceDO);
        return resourceDO.getId();
    }

    @Override
    public void updateResource(UpdateResourceDTO updateResourceDTO) {
        // 检查资源是否存在
        ResourceDO existingResource = resourceDao.getById(updateResourceDTO.getId());
        AssertUtils.notNull(existingResource, "资源不存在");
        AssertUtils.isTrue(ResourceStatusEnum.INIT.equals(existingResource.getStatus()), "当前状态不能编辑");

        // 如果修改了资源编码，需要检查新编码是否已存在
        if (!existingResource.getCode().equals(updateResourceDTO.getCode())) {
            ResourceDO resourceWithNewCode = resourceDao.getByCode(updateResourceDTO.getCode(), updateResourceDTO.getSystemId());
            if (resourceWithNewCode != null) {
                throw new BizException("资源编码已存在");
            }
        }

        // 转换并更新资源
        ResourceDO resourceDO = resourceConverter.toResourceDO(updateResourceDTO);
        resourceDO.setUpdateBy(EmployeeContextHolder.get().getId());
        resourceDao.updateById(resourceDO);
    }

    @Override
    public void deleteResource(Long resourceId) {
        // 检查资源是否存在
        ResourceDO existingResource = resourceDao.getById(resourceId);
        AssertUtils.notNull(existingResource, "资源不存在");
        AssertUtils.isTrue(ResourceStatusEnum.INIT.equals(existingResource.getStatus()), "当前状态不能删除");
        
        // 检查是否有子资源
        List<ResourceDO> children = resourceDao.getByParentId(resourceId);
        if (!children.isEmpty()) {
            throw new BizException("存在子资源，不能删除");
        }

        // 逻辑删除资源
        ResourceDO resourceDO = new ResourceDO();
        resourceDO.setId(resourceId);
        resourceDO.setDeleteTime(LocalDateTime.now());
        resourceDO.setUpdateBy(EmployeeContextHolder.get().getId());
        resourceDao.updateById(resourceDO);
    }

    @Override
    public void enableResource(Long resourceId) {
        // 检查资源是否存在
        ResourceDO existingResource = resourceDao.getById(resourceId);
        AssertUtils.notNull(existingResource, "资源不存在");
        
        // 检查当前状态
        if (ResourceStatusEnum.ENABLE.equals(existingResource.getStatus())) {
            return;
        }

        // 更新状态为启用
        ResourceDO resourceDO = new ResourceDO();
        resourceDO.setId(resourceId);
        resourceDO.setStatus(ResourceStatusEnum.ENABLE);
        resourceDO.setUpdateBy(EmployeeContextHolder.get().getId());
        resourceDao.updateById(resourceDO);
    }

    @Override
    public void disableResource(Long resourceId) {
        // 检查资源是否存在
        ResourceDO existingResource = resourceDao.getById(resourceId);
        AssertUtils.notNull(existingResource, "资源不存在");
        
        // 检查当前状态
        if (ResourceStatusEnum.DISABLE.equals(existingResource.getStatus())) {
            return;
        }

        // 更新状态为禁用
        ResourceDO resourceDO = new ResourceDO();
        resourceDO.setId(resourceId);
        resourceDO.setStatus(ResourceStatusEnum.DISABLE);
        resourceDO.setUpdateBy(EmployeeContextHolder.get().getId());
        resourceDao.updateById(resourceDO);
    }

    @Override
    public ResourceDTO getResourceById(Long resourceId) {
        ResourceDO resourceDO = resourceDao.getById(resourceId);
        return resourceDO != null ? resourceConverter.toResourceDTO(resourceDO) : null;
    }

    @Override
    public ResourceDTO getResourceByCode(String code, Long systemId) {
        ResourceDO resourceDO = resourceDao.getByCode(code, systemId);
        return resourceDO != null ? resourceConverter.toResourceDTO(resourceDO) : null;
    }

    @Override
    public List<ResourceDTO> getResourcesBySystemId(Long systemId) {
        List<ResourceDO> resourceDOList = resourceDao.getBySystemId(systemId);
        return resourceDOList.stream()
                .map(resourceConverter::toResourceDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<ResourceDTO> getResourcesByParentId(Long parentId) {
        List<ResourceDO> resourceDOList = resourceDao.getByParentId(parentId);
        return resourceDOList.stream()
                .map(resourceConverter::toResourceDTO)
                .collect(Collectors.toList());
    }

    @Override
    public IPage<ResourceDTO> resourcePage(ResourceCondition condition) {
        IPage<ResourceDO> page = resourceDao.page(condition);
        return page.convert(resourceConverter::toResourceDTO);
    }
}